package com.example.controller;

import com.example.entity.UploadFile;
import com.example.entity.User;
import com.example.entity.vo.UploadFileVO;
import com.example.security.SecurityUser;
import com.example.service.UploadFileService;
import com.example.service.UserService;
import com.example.util.CustomConstant;
import com.example.util.CustomUtil;
import com.example.util.ResultEntity;
import org.apache.ibatis.annotations.Param;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.util.UriUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.*;

@Controller
@RequestMapping("/uploadFile")
public class UploadFileController {

    @Autowired
    private UploadFileService uploadFileService;

    @Autowired
    private UserService userService;

    private UploadFileVO transformToUploadFileVO(UploadFile uploadFile) {
        UploadFileVO uploadFileVO = new UploadFileVO();
        BeanUtils.copyProperties(uploadFile, uploadFileVO);
        // 根据userId设置文件上传者
        Integer userId = uploadFile.getUserid();
        User user = userService.getById(userId);
        uploadFileVO.setUsername(user.getUsername());
        // 去除文件名标识符
        String fileName = uploadFileVO.getFilename();
        fileName = fileName.substring(fileName.indexOf('-') + 1);
        uploadFileVO.setFilename(fileName);
        return uploadFileVO;
    }


    @ResponseBody
    @RequestMapping("/get/all/uploadFiles.json")
    public ResultEntity<List<UploadFileVO>> getAllUploadFiles(@RequestParam("page") Integer page,
                                                              @RequestParam("limit") Integer limit,
                                                              @RequestParam(value = "id", required = false) Integer id,
                                                              @RequestParam(value = "username", required = false) String username,
                                                              @RequestParam(value = "fileName", required = false) String fileName,
                                                              @RequestParam(value = "beginDate", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date beginDate,
                                                              @RequestParam(value = "endDate", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date endDate
    ) {
        if (username != null) {
            if (username.isEmpty()) {
                username = null;
            } else {
                username = '%' + username + '%';
            }
        }
        if (fileName != null) {
            if (fileName.isEmpty()) {
                fileName = null;
            } else {
                fileName = '%' + fileName + '%';
            }
        }
        if (endDate != null) {
            // 将结束日期向后推迟一天
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(endDate);
            calendar.add(Calendar.DAY_OF_MONTH, 1);    // +1天
            endDate = calendar.getTime();
        }

        List<UploadFile> allUploadFiles = uploadFileService.getByExampleWithLimit(id, username, fileName, beginDate, endDate, page, limit);
        List<UploadFileVO> allUploadFileVOs = new ArrayList<>(allUploadFiles.size());
        for (UploadFile uploadFile : allUploadFiles) {
            UploadFileVO uploadFileVO = transformToUploadFileVO(uploadFile);
            allUploadFileVOs.add(uploadFileVO);
        }
        int count = uploadFileService.getCountByExample(id, username, fileName, beginDate, endDate);
        return ResultEntity.createResultEntity(0, null, count, allUploadFileVOs);
    }

    @RequestMapping("/download")
    public void download(@RequestParam("id") Integer id,
                         HttpSession session,
                         HttpServletRequest request,
                         HttpServletResponse response) {
        UploadFile uploadFile = uploadFileService.getById(id);
        String fileName = uploadFile.getFilename();
        String path = session.getServletContext().getRealPath("upload") + '\\' + fileName;
        // 去除文件名标识符
        fileName = fileName.substring(fileName.indexOf('-') + 1);
        OutputStreamWriter osw = null;
        InputStream in = null;
        OutputStream os = null;
        try {
            request.setCharacterEncoding("utf-8");
            // 下载文件需要设置消息头
            response.addHeader("content-Type", "application/octet-stream"); // MIME类型:二进制文件(任意文件)
            response.addHeader("content-Disposition", "attachment;filename=" + UriUtils.encode(fileName, "utf-8"));//filename包含后缀

            osw = new OutputStreamWriter(response.getOutputStream(), StandardCharsets.UTF_8);

            File file = new File(path);
            // 获取要下载的文件输入流
            in = new FileInputStream(file);
            // 如果不填setContentLength，不会报错，但是下载的时候会显示大小未知
            response.setContentLength((int) file.length());

            int len;
            // 创建数据缓冲区
            byte[] buffer = new byte[1024];
            // 通过response对象获取OutputStream流
            os = response.getOutputStream();
            // 将FileInputStream流写入到buffer缓冲区
            while ((len = in.read(buffer)) > 0) {
                // 将缓冲区的数据输出到客户端浏览器
                os.write(buffer, 0, len);
            }
        } catch (IOException e) {
            throw new RuntimeException(e.getMessage());
        } finally {
            try {
                if (osw != null) {
                    osw.close();
                }
                if (in != null) {
                    in.close();
                }
                if (os != null) {
                    os.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


    @ResponseBody
    @RequestMapping("/upload")
    public ResultEntity<Object> upload(@RequestParam("file") MultipartFile multipartFile, HttpSession session) throws IOException {
        String basePath = session.getServletContext().getRealPath("upload");
        String fileName = multipartFile.getOriginalFilename();
        if (fileName == null) {
            throw new RuntimeException(CustomConstant.MESSAGE_SYSTEM_ERROR_NULL_POINTER_EXCEPTION + "fileName");
        }
        fileName = UUID.randomUUID().toString().replace("-", "") + '-' + fileName;
        String filePath = basePath + '\\' + fileName;// 文件路径

        File desFile = new File(filePath);
        if (!desFile.getParentFile().exists()) {// 如果文件夹不存在则创建
            if (!desFile.mkdirs()) {
                throw new RuntimeException(CustomConstant.MESSAGE_SYSTEM_ERROR_MKDIRS);
            }
        }
        // 保存文件
        multipartFile.transferTo(desFile);

        // 保存数据库
        SecurityUser securityUser = CustomUtil.currentUser(session);
        User user = securityUser.getOriginalUser();
        UploadFile uploadFile = new UploadFile(user.getId(), fileName, new Date());
        uploadFileService.addUploadFile(uploadFile);

        return ResultEntity.createResultEntity(0, null, 0, null);
    }


    @PreAuthorize("hasRole('ROLE_2') or hasRole('ROLE_3') ")
    @ResponseBody
    @RequestMapping("/remove")
    public ResultEntity<Object> removeById(@Param("id") Integer id, HttpSession session) {
        try {
            UploadFile uploadFile = uploadFileService.getById(id);
            String fileName = uploadFile.getFilename();
            String path = session.getServletContext().getRealPath("upload") + '\\' + fileName;
            File file = new File(path);
            if (file.exists() && !file.delete()) {
                // 删除文件
                return ResultEntity.createResultEntity(-1, "", 0, null);
            }
            // 从数据库删除
            uploadFileService.removeById(id);
        } catch (Exception e) {
            return ResultEntity.createResultEntity(-1, e.getMessage(), 0, null);
        }
        return ResultEntity.createResultEntity(0, null, 0, null);
    }

    @PreAuthorize("hasRole('ROLE_2') or hasRole('ROLE_3') ")
    @ResponseBody
    @RequestMapping("/update")
    public ResultEntity<Object> updateById(@RequestBody UploadFile uploadFile, HttpSession session) {
        String basePath = session.getServletContext().getRealPath("upload") + '\\';

        // 旧文件
        String oldName = uploadFileService.getById(uploadFile.getId()).getFilename();
        File oldFile = new File(basePath + oldName);

        // 新文件
        String newName = uploadFile.getFilename();
        if (newName == null) {
            throw new RuntimeException(CustomConstant.MESSAGE_SYSTEM_ERROR_NULL_POINTER_EXCEPTION + "fileName");
        }
        newName = UUID.randomUUID().toString().replace("-", "") + '-' + newName;
        File newFile = new File(basePath + newName);

        // 重命名
        if (!oldFile.renameTo(newFile)) {
            return ResultEntity.createResultEntity(-1, "", 0, null);
        }

        // 更新数据库表
        uploadFile.setFilename(newName);
        uploadFileService.updateSelectiveById(uploadFile);
        return ResultEntity.createResultEntity(0, null, 0, null);
    }
}
